package com.spsoft.vatoutinv.service.vmsnvattrandtadvaltax.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.utils.*;
import com.spsoft.system.entity.NvatNegativestream;
import com.spsoft.system.entity.NvatRevenuemapself;
import com.spsoft.system.entity.NvatTrandtadvalextXinhua;
import com.spsoft.system.entity.NvatTrandtadvaltaxsep;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsenterpriseinfo.VmsEnterpriseInfo;
import com.spsoft.vatoutinv.entity.vmsepsInformation.VmsEpsInformation;
import com.spsoft.vatoutinv.entity.vmsfullbswjmanager.VmsFullBswjManager;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceDetails;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceItems;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceItemsExp;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.FpztEnum;
import com.spsoft.vatoutinv.enums.LzfpbzEnum;
import com.spsoft.vatoutinv.enums.NegeClEnum;
import com.spsoft.vatoutinv.mapper.VmsNvatTrandtadvaltaxsepMapper;
import com.spsoft.vatoutinv.model.bo.vmstransactionflowinvoice.VmsMergeBo;
import com.spsoft.vatoutinv.model.dto.transflowfindinvoice.TransFlowRecallInvoiceQueryDTO;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceInfoDto;
import com.spsoft.vatoutinv.model.dto.vmstransactionflowinvoice.*;
import com.spsoft.vatoutinv.model.vo.issueinvoice.ErrorVerifyVo;
import com.spsoft.vatoutinv.model.vo.transflowfindinvoice.TransFlowRecallInvoiceRespVO;
import com.spsoft.vatoutinv.model.vo.vmstransactionflowinvoice.*;
import com.spsoft.vatoutinv.service.issueinvoice.IssueInvoiceService;
import com.spsoft.vatoutinv.service.negativestream.NvatNegativestreamForVatService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsenterpriseinforisk.VmsEnterpriseInfoRiskService;
import com.spsoft.vatoutinv.service.vmsepsInformation.VmsEpsInformationService;
import com.spsoft.vatoutinv.service.vmsfullbswjmanager.VmsFullBswjManagerService;
import com.spsoft.vatoutinv.service.vmsnvattrandtadvaltax.VmsNvatRevenuemapselfService;
import com.spsoft.vatoutinv.service.vmsnvattrandtadvaltax.VmsNvatTrandtadvalextXinhuaService;
import com.spsoft.vatoutinv.service.vmsnvattrandtadvaltax.VmsNvatTrandtadvaltaxsepService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author wangy
 * @description 针对表【NVAT_TRANDTADVALTAXSEP(交易数据信息表（共性字段表）
 * 注：对应数据模版字段包含共性字段（本表字段）+扩展信息字段，扩展信息字段对应表必须包含交易号、数据来源字段，采集数据时会将交易数据拆分成两部分数据。业务类型字段在数据采集时，按照业务梳理的给交易数据打上业务类型字段标识。
 * 如果应税判定字段不在扩展信息表在扩展表某个字段引用的其他表中，则以那张表的主键作为应税判定字段。
 * 数据采集时，如果没有交易客户编码的数据通过开户帐号与客户映射找到对应的客户编号来存储。
 * 该表的字段顺序请勿调整会影响批量开票存储过程。)】的数据库操作Service实现
 * @createDate 2024-01-04 13:05:39
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VmsNvatTrandtadvaltaxsepServiceImpl extends ServiceImpl<VmsNvatTrandtadvaltaxsepMapper, NvatTrandtadvaltaxsep> implements VmsNvatTrandtadvaltaxsepService {

    public static final String LOG_MSG = "(流水开票实现层)";

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;

    private final VmsEnterpriseInfoRiskService vmsEnterpriseInfoRiskService;

    private final VmsFullBswjManagerService bswjManagerService;

    private final VmsEpsInformationService epsInformationService;

    private final IssueInvoiceService issueInvoiceService;

    private final VmsNvatTrandtadvalextXinhuaService nvatTrandtadvalextXinhuaService;

    private final VmsNvatRevenuemapselfService nvatRevenuemapselfService;

    private final NvatNegativestreamForVatService nvatNegativestreamForVatService;

    /**
     * 检查开票人状态
     */
    @Override
    public void checkStatus(String type) {
        String deptCode = SecurityUtils.getDeptCode();
        // 开票方纳税人状态
        vmsEnterpriseInfoService.checkStatus(deptCode, type);
        // 风险纳税人校验
        vmsEnterpriseInfoRiskService.checkStatus(deptCode, type);

    }

    @Override
    public Result<IPage<VmsTransactionFlowInvoicePageVo>> getTransactionFlowInvoiceList(VmsTransactionFlowInvoicePageDto vmsTransactionFlowInvoicePageDto) {
        // 创建返回对象
        Integer pageNo = vmsTransactionFlowInvoicePageDto.getPageNo();
        Integer pageSize = vmsTransactionFlowInvoicePageDto.getPageSize();
        Page<VmsTransactionFlowInvoicePageVo> page = new Page<>(pageNo, pageSize); // 获取分页对象
        // 获取交易流水开票列表
        IPage<VmsTransactionFlowInvoicePageVo> transactionFlowInvoiceList = baseMapper.getTransactionFlowInvoiceList(page, SecurityUtils.getDeptCode(), vmsTransactionFlowInvoicePageDto);
        return Result.OK(transactionFlowInvoiceList);
    }

    @Override
    public Result<VmsManualInvoiceVo> getInvoiceInfoByTransactionFlow(List<Long> ids) {
        if (ids.size() > 999) { // 判断ids的数量,如果超过1000个,好像就超过sql in属性,就会报错.
            return Result.ERROR(ResponseEnum.EXCESSIVE_INVOICE_FLOW);
        }
        // 校验开票人状态 风险等级
        checkStatus("1"); // checkStatus，调用俩接口，检查开票方纳税人状态和风险纳税人校验
        // 根据 id查询流水信息
        List<VmsTransacitonFlowInvoiceItemVo> itemVo = baseMapper.selectInvoiceByIds(ids); // 调用了一个baseMapper方法,传入了ids. xml里 会使用sql查询,并且循环ids里的每个id,进行判断. 得到指定的对象.
        // 校验所选流水是否都为正数流水 是否都为同一获票人
        checkInvoiceRule(itemVo, "");
        // 构建返回对象
        VmsManualInvoiceVo vo = new VmsManualInvoiceVo();
        if (itemVo.isEmpty()) { // 如果有发票流水,但是没有根据流程id 找流水信息
            throw new BusinessException(ResponseEnum.NO_FLOW_INFORMATION_FOUND);
        }
        // 使用部门代码查询开票方（销售方）信息
        String deptCode = SecurityUtils.getDeptCode();
        // 开票方信息
        VmsEnterpriseInfo enterpriseInfo = vmsEnterpriseInfoService.getInfoByRedis(deptCode);
        // 版式文件信息
        VmsFullBswjManager oneByWhjg = bswjManagerService.getOneByWhjg(deptCode);
        if (ObjectUtil.isEmpty(oneByWhjg)) { // 没有板式文件,就报错了.
            throw new BusinessException(ResponseEnum.FULL_BSWJ_ERROR_01);
        }
        // 开票方名称
        String kpfmc = enterpriseInfo.getNsrmc();
        // 开票方纳税人识别号
        String kpfnsrsbh = enterpriseInfo.getNsrsbh();
        // 开票人
        String kpr = SecurityUtils.getUsername();
        // 购买方名称
        String gmfmc = itemVo.get(0).getKfhm();
        // 购买方纳税人识别号
        String gmfnsrsbh = itemVo.get(0).getNsrsbh();

        // 发票主体信息
        VmsManualBaseVo vmsManualBaseVo = new VmsManualBaseVo();
        vmsManualBaseVo.setGmfmc(gmfmc);
        vmsManualBaseVo.setGmfnsrsbh(gmfnsrsbh);
        vmsManualBaseVo.setXsfmc(kpfmc);
        vmsManualBaseVo.setXsfnsrsbh(kpfnsrsbh);
        vmsManualBaseVo.setKpr(kpr);

        if (itemVo.size() == 1 && StringUtil.isNotEmpty(itemVo.get(0).getBz())) { // 为啥这里只有一个,并且备注不为空的情况下, 会设置值为第一个?  -- 没理解
            vmsManualBaseVo.setBz(itemVo.get(0).getBz());
        }


        // 发票明细信息
        List<VmsManualDetailVo> vmsManualDetailVoList = getVmsManualDetailVos(itemVo, vmsManualBaseVo); // 把发票明细行添加了
        vo.setVmsManualDetailVoList(vmsManualDetailVoList); // 设置明细行到列表里
        vmsManualBaseVo.setJshjText(MoneyUtils.toChinese(StringUtil.toString(vmsManualBaseVo.getJshj()))); // 价税合计,并且添加中文的
        vo.setVmsManualBaseVo(vmsManualBaseVo); // 基本信息部分

        // 扩展信息
        VmsManualExtendVo vmsManualExtendVo = new VmsManualExtendVo(); // 拓展信息部分
        if (StringUtil.isNotEmpty(gmfmc) && StringUtil.isEmpty(vmsManualBaseVo.getGmfnsrsbh())) { // 有购买方名称,并且没纳税人识别号
            vmsManualExtendVo.setGmfzrrbz(CommonEnum.PERSON_FLAG_01.getKey());
        } else {
            vmsManualExtendVo.setGmfzrrbz(CommonEnum.PERSON_FLAG_02.getKey()); // 设置标志 , 否
        }

        vmsManualExtendVo.setXsfdz(enterpriseInfo.getScjydz());
        vmsManualExtendVo.setXsfdh(enterpriseInfo.getZcdlxdh());
        vmsManualExtendVo.setXsfzh(enterpriseInfo.getYhzh());
        vmsManualExtendVo.setXsfkhh(enterpriseInfo.getKhhmc());
        vmsManualExtendVo.setSkyhmc(enterpriseInfo.getKhhmc());
        vmsManualExtendVo.setSkyhzh(enterpriseInfo.getYhzh());
        vmsManualExtendVo.setQydm(oneByWhjg.getQydm());
        vmsManualExtendVo.setYsxwfsd(oneByWhjg.getQymc());
        vo.setVmsManualExtendVo(vmsManualExtendVo);

        return Result.OK(vo);
    }

    @NotNull
    private List<VmsManualDetailVo> getVmsManualDetailVos(List<VmsTransacitonFlowInvoiceItemVo> itemVo, VmsManualBaseVo vmsManualBaseVo) {
        List<VmsManualDetailVo> vmsManualDetailVoList = new ArrayList<>(); // 创建一个列表,并且返回的  发票明细列表
        Map<String, VmsEpsInformation> epsMap = new HashMap<>(); // 一个对象,key是字符串, 值是数据库VMS_EPS_INFORMATION的对象.
        // 明细序号
        int mxxh = 1;
        // 定义合计金额
        BigDecimal hjje = BigDecimal.ZERO; // 大数字的0 - java中定义的常量,直接使用.
        // 定义合计税额
        BigDecimal hjse = BigDecimal.ZERO; // 定义几个金额
        // 定义合计交易金额
        BigDecimal jyje = BigDecimal.ZERO;
        for (VmsTransacitonFlowInvoiceItemVo item : itemVo) { // 列表进行循环,
            BigDecimal sl4 = item.getSysl().setScale(4); // 税率,当前值保留4位
            VmsEpsInformation epsInformation = epsMap.get(sl4.toString()); // 根据税率,获取对应的eps信息.(企业商品及服务信息管理表)
            if (ObjectUtil.isEmpty(epsInformation)) {
                epsMap.put(sl4.toString(), epsInformationService.getInfoBySlv(sl4.toString())); // 为空再次查找一下数据, 根据税率查找,对应的企业商品表?
                epsInformation = epsMap.get(sl4.toString());
            }
            VmsManualDetailVo vmsManualDetailVo = new VmsManualDetailVo(); // 商品表的详细对象
            vmsManualDetailVo.setId(item.getId()); // 设置主键id
            ArrayList<String> list = new ArrayList<>();
            // 简称 名称
            if (ObjectUtil.isEmpty(epsInformation)) { // 如果初始化没数据,并且发请求还是没数据,就报错.
                throw new BusinessException(ResponseEnum.PRODUCT_INFORMATION_IS_EMPTY);
            }
            String sphfwfljc = epsInformation.getSphfwfljc(); // 获取商品分类及名称的简称? -- 提示的
            String sphfwmc = epsInformation.getEpsName(); // 获取商品名称
            list.add("*" + sphfwfljc + "*" + item.getXzjc()); // 获取险种简称
            list.add("*" + sphfwfljc + "*" + sphfwmc); // sphfwfljc + sphfwmc
            vmsManualDetailVo.setXmmc(list.get(0)); // 项目名称
            vmsManualDetailVo.setMxxh((long) mxxh++); // 明细序号
            vmsManualDetailVo.setXmmcList(list); // 多个项目名称
            vmsManualDetailVo.setGgxh(item.getExpcol1()); // 规格型号
            vmsManualDetailVo.setDw(item.getJldw()); // 计量单位
            // 流水数量都为 1
            if (ObjectUtil.isEmpty(item.getXmsl())) { // 项目数量如果是空的, 那就设置为"1"
                vmsManualDetailVo.setSl(CommonConstant.STR_1);
            } else {
                vmsManualDetailVo.setSl(item.getXmsl().toPlainString()); // toPlaingString 设置一个普通字符串
            }
            String dj = formatBigDecimalToString(item.getBhsje().divide(new BigDecimal(vmsManualDetailVo.getSl()), 25, RoundingMode.HALF_UP)); // 最大长度25位的字符串
            vmsManualDetailVo.setDj(dj); // 单价设置到对象里
            if (ObjectUtil.isNotEmpty(item.getXmdj())) { // 项目单价,是否有值
                vmsManualDetailVo.setHsdj(item.getXmdj().toPlainString());
            }
            vmsManualDetailVo.setJe(item.getBhsje());
            vmsManualDetailVo.setSlv(item.getSysl());
            vmsManualDetailVo.setSe(item.getXxse());
            hjje = hjje.add(item.getBhsje()); // hjje - 合计金额 = 不含税金额+ 税额
            hjse = hjse.add(item.getXxse()); // hjse = 0 + 税额
            jyje = jyje.add(item.getJyje()); // 交易金额 = 0 + 交易金额
            vmsManualDetailVoList.add(vmsManualDetailVo); // 明细列表
        }
        vmsManualBaseVo.setJshj(jyje); // 设置价税合计
        return vmsManualDetailVoList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> invoiceByTransactionFlow(VmsTransactionFlowInvoiceDto dto) {
        // 获取流水明细里面的 id 属性
        List<Long> ids = dto.getVmsManualDetailDto().stream().map(VmsManualDetailDto::getId).collect(Collectors.toList()); // 把传入的发票明细里,获得全部的id(好像是项目id)
        // 获取发票类型
        String fppz = dto.getVmsManualBaseDto().getFppz(); // 发票类型,从基本信息里获得.
        // 根据 id 查询流水是否包含负数流水
        List<VmsTransacitonFlowInvoiceItemVo> list = baseMapper.selectInvoiceByIds(ids);
        // 校验开具发票规则
        checkInvoiceRule(list, fppz); // 检查是否不符合流程,比如 负数流水必须先红冲.
        if (CommonEnum.INVOICE_TYPE_01.getKey().equals(fppz) && StringUtil.isEmpty(dto.getVmsManualBaseDto().getGmfnsrsbh())) {
            throw new BusinessException(ResponseEnum.SPECIAL_INVOICE_TAX_NUMBER_CANNOT_BE_EMPTY);
        }
        // 判断如果是 普票 非自然人 购买方纳税人识别号不能为空
        String gmfzrrbz = dto.getVmsManualExtendDto().getGmfzrrbz();
        if (CommonEnum.PERSON_FLAG_02.getKey().equals(gmfzrrbz)
                && StringUtil.isEmpty(dto.getVmsManualBaseDto().getGmfnsrsbh())) {
            throw new BusinessException(ResponseEnum.GMFZRR_GMFNSRSBH_ERROR);
        }
        // 修改流水状态 03
        return manualInvoice(dto);
    }

    @Transactional
    public Result<Object> manualInvoice(VmsTransactionFlowInvoiceDto dto) {
        // 流水开票-发票主信息对象
        VmsManualBaseDto vmsManualBaseDto = dto.getVmsManualBaseDto();
        // 流水开票-发票明细信息
        List<VmsManualDetailDto> vmsManualDetailDto = dto.getVmsManualDetailDto();
        // 流水开票-非必填字段扩展信息对象
        VmsManualExtendDto vmsManualExtendDto = dto.getVmsManualExtendDto();
        // 已开发票接口 需要准备的数据
        List<VmsFullOutInvoiceInfoDto> vmsFullOutInvoiceInfoDtos = new ArrayList<>();
        // 单个 已开发票信息
        VmsFullOutInvoiceInfoDto vmsFullOutInvoiceInfoDto = new VmsFullOutInvoiceInfoDto();

        // 销售方信息
        VmsEnterpriseInfo enterpriseInfo = vmsEnterpriseInfoService.getInfoByRedis(SecurityUtils.getDeptCode());
        // 根据流水信息累计的合计金额
        BigDecimal sumhjje = BigDecimal.ZERO;
        // 根据流水信息累计的合计税额
        BigDecimal sumhjse = BigDecimal.ZERO;
        // 根据流水信息累计的合计交易金额
        BigDecimal sumjyje = BigDecimal.ZERO;
        // 已开发票信息-发票主体信息
        VmsFullOutInvoiceDetails detail = new VmsFullOutInvoiceDetails();


        detail.setLzfpbz(LzfpbzEnum.BULE.getKey());
        detail.setFppz(vmsManualBaseDto.getFppz());
        detail.setJems(CommonEnum.AMOUNT_MODE_01.getKey());
        detail.setGmfmc(vmsManualBaseDto.getGmfmc());
        detail.setGmfnsrsbh(vmsManualBaseDto.getGmfnsrsbh());
        detail.setXsfmc(enterpriseInfo.getNsrmc());
        detail.setXsfnsrsbh(enterpriseInfo.getNsrsbh());
        detail.setKpr(SecurityUtils.getUsername());
        detail.setKprq(new Date());
        detail.setBz(vmsManualBaseDto.getBz());
        detail.setSczt(CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey());
        detail.setFpzt(FpztEnum.NORMAL.getKey());
        detail.setQydjid(SecurityUtils.getDeptCode());
        detail.setSjly(CommonEnum.DATA_SOURCE_0.getKey());
        detail.setPpzt(CommonEnum.MATCHING_STATUS_1.getKey());
        detail.setSfbdc(CommonEnum.SFBDC_NO.getKey());
        detail.setZsfs(CommonEnum.TAXATION_METHOD_0.getKey());
        detail.setKpzt(CommonEnum.KPZT_0.getKey());
        detail.setDelFlag(CommonEnum.DEL_STATUS_0.getKey());
        detail.setCreatTime(new Date());
        detail.setUpdateTime(new Date());
        detail.setCreatBy(SecurityUtils.getUserCode());
        detail.setUpdateBy(SecurityUtils.getUserCode());


        // 发票明细
        ArrayList<VmsFullOutInvoiceItems> items = new ArrayList<>();
        // 存储流水id的集合
        ArrayList<Long> lsIds = new ArrayList<>(vmsManualDetailDto.size());
        // 以流水id为key 项目名称为value的map
        Map<Long, String> map = new HashMap<>();
        for (int i = 0; i < vmsManualDetailDto.size(); i++) {
            VmsManualDetailDto detailItem = vmsManualDetailDto.get(i);
            lsIds.add(detailItem.getId());
            map.put(detailItem.getId(), detailItem.getXmmc());
        }
        List<VmsTransacitonFlowInvoiceItemVo> itemVo = baseMapper.selectInvoiceByIds(lsIds);
        Map<String, VmsEpsInformation> slMap = new HashMap<>();
        for (int i = 0; i < itemVo.size(); i++) {
            VmsFullOutInvoiceItems item = new VmsFullOutInvoiceItems();
            VmsTransacitonFlowInvoiceItemVo vmsTransacitonFlowInvoiceItemVo = itemVo.get(i);
            item.setXmmc(map.get(vmsTransacitonFlowInvoiceItemVo.getId()));
            item.setMxxh((long) i + 1);
            item.setGgxh(vmsTransacitonFlowInvoiceItemVo.getExpcol1());
            item.setDw(vmsTransacitonFlowInvoiceItemVo.getJldw());
            if (ObjectUtil.isNotEmpty(vmsTransacitonFlowInvoiceItemVo.getXmsl())) {
                item.setSl(vmsTransacitonFlowInvoiceItemVo.getXmsl().toPlainString());
            }
            if (ObjectUtil.isNotEmpty(vmsTransacitonFlowInvoiceItemVo.getXmdj())) {
                item.setDj(vmsTransacitonFlowInvoiceItemVo.getXmdj().toPlainString());
            }
            item.setJe(vmsTransacitonFlowInvoiceItemVo.getBhsje());
            item.setSlv(vmsTransacitonFlowInvoiceItemVo.getSysl());
            BigDecimal sl4 = vmsTransacitonFlowInvoiceItemVo.getSysl().setScale(4);
            VmsEpsInformation eps = slMap.getOrDefault(sl4.toString(), epsInformationService.getInfoBySlv(sl4.toString()));
            // 如果该条流水税率 在商品信息中未配置
            if (ObjectUtil.isEmpty(eps)) {
                throw new BusinessException(ResponseEnum.ABNORMAL_INVOICING_TRANSACTION_FLOW_01);
            }
            item.setSe(vmsTransacitonFlowInvoiceItemVo.getXxse());
            item.setKce(new BigDecimal(0));
            item.setFphxz(CommonEnum.FPHXZ_00.getKey());
            item.setCpbm(eps.getEpsCode());
            item.setCreatTime(new Date());
            item.setCreatBy(SecurityUtils.getUserCode());
            if (StringUtil.isNotEmpty(eps.getGstcmCode())) {
                item.setSphfwssflhbbm(eps.getGstcmCode());
            }
            if (StringUtil.isNotEmpty(eps.getJsff())) {
                item.setJsff(eps.getJsff());
            }
            if (StringUtil.isNotEmpty(eps.getZsxm())) {
                item.setZsxm(eps.getZsxm());
            }
            if (StringUtil.isNotEmpty(eps.getYhzcbs())) {
                item.setYhzcbs(eps.getYhzcbs());
            }

            items.add(item);

            sumhjje = sumhjje.add(item.getJe());
            sumhjse = sumhjse.add(item.getSe());
            sumjyje = sumjyje.add(vmsTransacitonFlowInvoiceItemVo.getJyje());
            item.setRdid(StringUtil.toString(vmsTransacitonFlowInvoiceItemVo.getId()));
        }
        vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsList(items);

        // 设置 合计金额 合计税额
        detail.setHjje(sumhjje);
        detail.setHjse(sumhjse);
        detail.setJshj(sumjyje);
        vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceDetails(detail);

        // 发票扩展信息
        if (ObjectUtil.isNotEmpty(vmsManualExtendDto)) {
            VmsFullOutInvoiceItemsExp invoiceItemsExp = new VmsFullOutInvoiceItemsExp();
            BeanUtils.copyBeanProp(invoiceItemsExp, vmsManualExtendDto);
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsExp(invoiceItemsExp);
        }
        vmsFullOutInvoiceInfoDtos.add(vmsFullOutInvoiceInfoDto);
        // 修改流水状态
        for (Long lsId : lsIds) {
            LambdaUpdateWrapper<NvatTrandtadvaltaxsep> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(NvatTrandtadvaltaxsep::getLszt, 3L)
                    .set(NvatTrandtadvaltaxsep::getWkpje, BigDecimal.ZERO)
                    .eq(NvatTrandtadvaltaxsep::getRdid, lsId)
                    .eq(NvatTrandtadvaltaxsep::getLszt, 1L);
            boolean update = update(updateWrapper);
            if (update) {
                log.info("{}修改流水状态成功,流水id:{}", LOG_MSG, lsId);
            } else {
                log.info("{}修改流水状态失败,流水id:{}", LOG_MSG, lsId);
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new BusinessException(ResponseEnum.FLOW_STATUS_UPDATE_FAIL);
            }
        }
        Result<Object> result = issueInvoiceService.issueInvoice(vmsFullOutInvoiceInfoDtos, SecurityUtils.getTokenUser());
        if (ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            return Result.OK("处理完毕，请在【已开发票管理】中进行发票上传操作！");
        } else {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }
    }

    @Override
    public Result<IPage<TransFlowRecallInvoiceRespVO>> queryTransflow(TransFlowRecallInvoiceQueryDTO queryDTO) {
        // 创建返回对象
        Integer pageNo = queryDTO.getPageNo();
        Integer pageSize = queryDTO.getPageSize();
        Page<TransFlowRecallInvoiceRespVO> page = new Page<>(pageNo, pageSize);
        List<String> jyjgs = null;
        if (StringUtil.isNotBlank(queryDTO.getJyjg())) {
            jyjgs = Arrays.asList(queryDTO.getJyjg().split(","));

        }
        // 获取交易流水开票列表
        IPage<TransFlowRecallInvoiceRespVO> transflowPage = baseMapper.queryTransflow(page, queryDTO, jyjgs);
        return Result.OK(transflowPage);
    }

    // 校验开票规则
    private void checkInvoiceRule(List<VmsTransacitonFlowInvoiceItemVo> list, String fppz) {
        String roleName = SecurityUtils.getTokenUser().getRoleName(); // 获取角色名称
        if (!list.isEmpty()) { // 如果发票列表是有值的
            // 获票人名称
            String kfhm = list.get(0).getKfhm();
            list.forEach(item -> {
                // 校验是否为同一获票人
                if (!kfhm.equals(item.getKfhm())) {// 循环校验都是同一个获票人
                    throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INVOICE_TICKET_RECIPIENT);
                }
                // 2 红字 证明是负数流水
                if (item.getBhsje().compareTo(BigDecimal.ZERO) < 0) { // 数字是负数, 那就是负数流水
                    // 若roleName为“财务管理岗” 该负数流水交易数据处理前，请先进行蓝字发票冲红操作！若已进行发票冲红操作，请在交易流水匹配模块处理该流水！
                    if ("财务发票管理岗".equals(roleName) || "业务开票岗位".equals(roleName)) {// 一个发票需要先红冲操作,才能开具专票的流水处理?
                        throw new BusinessException(ResponseEnum.VERIFICATION_INVOICING_ROLES_IN_FLOW_CHART_01); //
                    } else {
                        // 您无该类型流水操作权限，请联系财务管理人员进行处理！
                        throw new BusinessException(ResponseEnum.VERIFICATION_INVOICING_ROLES_IN_FLOW_CHART_02);
                    }
                }
                // 开具专票时,不能选择税率为零的数据
                if (StringUtil.isNotEmpty(fppz)) {
                    if ("0".equals(StringUtil.toString(item.getSysl())) && "01".equals(fppz)) { // 票种位01,并且 税率为0,不允许操作.
                        throw new BusinessException(ResponseEnum.VERIFICATION_TAX_RATE_FOR_INVOICING_ON_DAILY_BASIS);
                    }
                }
            });
        } else {
            throw new BusinessException(ResponseEnum.NO_FLOW_INFORMATION_FOUND);
        }
    }

    /**
     * 将BigDecimal转为String
     * String的最大长度为25
     */
    private String formatBigDecimalToString(BigDecimal bigDecimal) {
        if (ObjectUtil.isEmpty(bigDecimal)) {
            return StringUtils.EMPTY;
        }
        // 单价、数量先保留6位小数
        String formatResult = bigDecimal.setScale(6, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
        if (formatResult.length() > 25) {
            formatResult = formatResult.substring(0, 25);
        }
        return formatResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> splitTransactionFlow(VmsFlowSplitDto dto) {
        Long id = dto.getId();
        // 1.校验流水ID是否正确
        NvatTrandtadvaltaxsep nvatTrandtadvaltaxsep = getNvatTrandtadvaltaxsepById(id, true); // 使用了一些序列化,获取一个对象. -- 可能 是一个中间表的对象, 这里有原本的表数据,有新表的id等..
        NvatTrandtadvalextXinhua xinhua = nvatTrandtadvalextXinhuaService.getById(id);
        // 1.1 判断流水是否为空
        if (nvatTrandtadvaltaxsep == null || xinhua == null) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_DOES_NOT_EXIST);
        }
        // 校验是否为负数流水,后续需要有额外处理
        boolean fslsFlag = nvatTrandtadvaltaxsep.getJyje().compareTo(BigDecimal.ZERO) < 0;
        // 校验
        List<ErrorVerifyVo> errorVerifyList = verification(nvatTrandtadvaltaxsep, xinhua, dto, fslsFlag, id);
        if (CollectionUtil.isNotEmpty(errorVerifyList)) {
            log.error("{}校验不通过：{}", LOG_MSG + "-流水拆分", JSONObject.toJSONString(errorVerifyList));
            return Result.ERROR(ResponseEnum.ISSUE_INVOICE_VERIFY_ERROR, errorVerifyList);
        }

        log.info("{}-拆分流水信息校验通过,流水ID:{}", LOG_MSG, id);

        // 2. 开始拆分
        // 2.1 修改原流水状态为已拆分 修改 NVAT_TRANDTADVALTAXSEP 状态
        LambdaUpdateWrapper<NvatTrandtadvaltaxsep> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(NvatTrandtadvaltaxsep::getCfhbzt, CommonEnum.SPLIT_MERGE_STATUS_2.getKey())
                .eq(NvatTrandtadvaltaxsep::getRdid, id)
                .eq(NvatTrandtadvaltaxsep::getLszt, CommonEnum.FLOW_INVOICE_STATUS_1.getKey())
                .eq(NvatTrandtadvaltaxsep::getCfhbzt, CommonEnum.SPLIT_MERGE_STATUS_1.getKey());
        boolean update = update(updateWrapper);
        if (!update) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_SPLIT_FAILED);
        }
        // 如果是负数流水 需要去处理负数流水表
        if (fslsFlag) {
            boolean update1 = nvatNegativestreamForVatService.update(new LambdaUpdateWrapper<NvatNegativestream>()
                    .set(NvatNegativestream::getClzt, CommonEnum.NEGATIVE_FLOW_STATUS_1.getKey())
                    .set(NvatNegativestream::getCzr, SecurityUtils.getUsername())
                    .set(NvatNegativestream::getCzrq, new Date())
                    .set(NvatNegativestream::getCllx, NegeClEnum.CLLX_06.getKey())
                    .set(NvatNegativestream::getCzsm, NegeClEnum.CLLX_06.getValue())
                    .eq(NvatNegativestream::getRdid, id)
                    .eq(NvatNegativestream::getClzt, CommonEnum.NEGATIVE_FLOW_STATUS_0.getKey()));
            if (!update1) {
                throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_SPLIT_FAILED);
            }
        }
        log.info("{}-修改原流水状态为已拆分成功,流水ID:{}", LOG_MSG, id);


        // 2.2 被拆分的流水ID对应 NVAT_REVENUEMAPSELF yrdid 做关联
        // 对应 NVAT_TRANDTADVALTAXSEP,NVAT_TRANDTADVALEXT_XINHUA RDID
        // 对应 NVAT_REVENUEMAPSELF xrdid
        Long yrdid = id;
        for (int i = 0; i < dto.getItem().size(); i++) {
            VmsFlowSplitDto.VmsFlowSplitItem vmsFlowSplitItem = dto.getItem().get(i);
            // 2.2.1 插入 NVAT_TRANDTADVALTAXSEP 拆分信息
            NvatTrandtadvaltaxsep nvatTrandtadvaltaxsep1 = new NvatTrandtadvaltaxsep();
            BeanUtils.copyBeanProp(nvatTrandtadvaltaxsep1, nvatTrandtadvaltaxsep);
            nvatTrandtadvaltaxsep1.setRdid(null);
            nvatTrandtadvaltaxsep1.setJyje(vmsFlowSplitItem.getHsje());
            nvatTrandtadvaltaxsep1.setJyrmbje(vmsFlowSplitItem.getHsje());
            nvatTrandtadvaltaxsep1.setBhsje(vmsFlowSplitItem.getBhsje());
            nvatTrandtadvaltaxsep1.setXxse(vmsFlowSplitItem.getSe());
            nvatTrandtadvaltaxsep1.setWkpje(vmsFlowSplitItem.getHsje());
            nvatTrandtadvaltaxsep1.setCfhbzt(Long.valueOf(CommonEnum.SPLIT_MERGE_STATUS_1.getKey()));
            nvatTrandtadvaltaxsep1.setLszt(Long.valueOf(CommonEnum.FLOW_INVOICE_STATUS_1.getKey()));
            save(nvatTrandtadvaltaxsep1);

            Long xrdid = nvatTrandtadvaltaxsep1.getRdid();


            // 2.2.2 插入 NVAT_TRANDTADVALEXT_XINHUA 拆分信息
            NvatTrandtadvalextXinhua xinhua1 = new NvatTrandtadvalextXinhua();
            BeanUtils.copyBeanProp(xinhua1, xinhua);
            xinhua1.setRdid(xrdid);
            xinhua1.setXmsl(BigDecimal.ONE);
            nvatTrandtadvalextXinhuaService.save(xinhua1);

            // 2.2.3 插入 NVAT_REVENUEMAPSELF 拆分信息
            NvatRevenuemapself nvatRevenuemapself = new NvatRevenuemapself();
            nvatRevenuemapself.setYrdid(yrdid);
            nvatRevenuemapself.setXrdid(xrdid);
            nvatRevenuemapself.setCzlx(CommonEnum.SPLIT_MERGE_TYPE_1.getKey());
            nvatRevenuemapself.setCzsj(new Date());
            nvatRevenuemapselfService.save(nvatRevenuemapself);

            // 2.2.4 判断是否为负数流水
            if (fslsFlag) {
                NvatNegativestream nvatNegativestream = new NvatNegativestream();
                nvatNegativestream.setRdid(xrdid);
                nvatNegativestream.setYwbh(nvatTrandtadvaltaxsep1.getYsjyls());
                nvatNegativestream.setFuywbh(nvatTrandtadvaltaxsep1.getExpcol1());
                nvatNegativestream.setTbr(nvatTrandtadvaltaxsep1.getKhmc());
                nvatNegativestream.setJyjg(nvatTrandtadvaltaxsep1.getJyjg());
                nvatNegativestream.setSbrq(new Date());
                nvatNegativestream.setClzt(CommonEnum.NEGATIVE_FLOW_STATUS_0.getKey());
                nvatNegativestream.setSfgz(CommonEnum.NEGATIVE_FLOW_MANAGE_0.getKey());
                nvatNegativestreamForVatService.save(nvatNegativestream);
            }
            log.info("{}-获取拆分流水ID成功,流水ID:{}", LOG_MSG, xrdid);
        }
        return Result.OK("拆分流水成功");
    }

    @Override
    public Result<IPage<VmsMergeQueryVo>> mergeQuery(VmsMergeDto dto) {
        String bh = getBh(dto);
        Integer pageNo = dto.getPageNo();
        Integer pageSize = dto.getPageSize();
        Page<VmsMergeQueryVo> page = new Page<>(pageNo, pageSize);
        String ywhh = null;
        String tbdh = null;
        if (CommonEnum.MERGE_QUERY_CONDITION_0.getKey().equals(dto.getMergeQueryCondition())) {
            ywhh = bh;
        } else {
            tbdh = bh;
        }
        IPage<VmsMergeQueryVo> list = this.baseMapper.mergePageQuery(page, ywhh, tbdh, SecurityUtils.getDeptCode());
        return Result.OK(list);
    }

    /**
     * 验证合并选择的数据并且返回编号
     *
     * @param dto
     * @return
     */
    private String getBh(VmsMergeDto dto) {
        // >?? 总结: 使用dto的YRidid 判断是否已经合并或者拆分, 然后判断是业务编号还是投保单号,最终返回对应的编号.

        // 1.校验流水ID是否正确
        // ??? -- 是不是用这id, 去俩表里查询数据?  --
        NvatTrandtadvaltaxsep p = getNvatTrandtadvaltaxsepById(dto.getRdid(), true); // 根据id,获取了一个数据.
        NvatTrandtadvalextXinhua xinhua = nvatTrandtadvalextXinhuaService.getNvatTrandtadvalextXinhuaById(dto.getRdid()); // 根据外键,获取交易数据ID

        if (p == null || xinhua == null) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_DOES_NOT_EXIST);
        }

        // 1.3 判断流水是否已拆分 或 已合并
        int count = nvatRevenuemapselfService.count(new LambdaQueryWrapper<NvatRevenuemapself>() // Yrdid 判断,每个对象里的Yrdid 已经合并或者已经拆分的参数.
                .eq(NvatRevenuemapself::getYrdid, dto.getRdid())
        );
        if (count > 0) {
            throw new BusinessException(ResponseEnum.THE_DATA_DOES_NOT_MEET_THE_MERGING_REQUIREMENTS);
        }
        // 是0就从if走 业务编号 , 如果是1, 就是 投保单号
        if (CommonEnum.MERGE_QUERY_CONDITION_0.getKey().equals(dto.getMergeQueryCondition())) {
            return p.getExpcol1();
        } else {
            return xinhua.getTbdh();
        }
    }

    @Override
    public Result<List<VmsMergeQueryVo>> preMerge(VmsMergeDto dto) {

        List<VmsMergeBo> list = mergeRes(dto);
        //合并后数据重新计算并转换
        if (list.size() > 0) { // 这些地方为啥要判断下
            List<VmsMergeQueryVo> relist = BeanUtils.copyListProperties(list, VmsMergeQueryVo::new);
            return Result.OK(relist);
        }

        return Result.OK(new ArrayList<>());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Object> merge(VmsMergeDto dto) {
        List<VmsMergeBo> list = mergeRes(dto);
        log.info("{}-合并后数据共计：{}条", LOG_MSG, list.size());
        if (CollectionUtil.isNotEmpty(list)) {
            //如果 是一条数据合并的， 直接报错
            if (list.size() == 1) {
                if (list.get(0).getRdids().size() == 1) {
                    return Result.ERROR(ResponseEnum.MERGING_TRANSACTION_FLOW_ONE_ERROR);
                }
            }
            for (VmsMergeBo bo : list) {
                log.info("{}-合并后数据处理：{}", LOG_MSG, JSONUtil.toJsonStr(bo)); // 转换为json格式的字符串
                //1.查询到要处理的合并的数据
                List<NvatTrandtadvaltaxsep> tps = this.list(
                        new LambdaQueryWrapper<NvatTrandtadvaltaxsep>()
                                .in(NvatTrandtadvaltaxsep::getRdid, bo.getRdids())
                                .eq(NvatTrandtadvaltaxsep::getCfhbzt, CommonEnum.SPLIT_MERGE_STATUS_1.getKey())
                                .eq(NvatTrandtadvaltaxsep::getLszt, CommonEnum.FLOW_INVOICE_STATUS_1.getKey())
                                .eq(NvatTrandtadvaltaxsep::getJyjg, SecurityUtils.getDeptCode())
                );

                if (bo.getRdids().size() != tps.size()) {
                    //处理的数据和实际数据不一致
                    throw new BusinessException(ResponseEnum.MERGING_ERROR);
                }
                NvatTrandtadvaltaxsep np = new NvatTrandtadvaltaxsep();
                BeanUtils.copyProperties(tps.get(0), np); // 实例给到了列表的第一个
                NvatTrandtadvalextXinhua xinhua = nvatTrandtadvalextXinhuaService.getById(np.getRdid()); // 应该是mp的根据id直接获取的逻辑
                if (xinhua == null) { // 新华里没这个数据 ,就报错了.
                    throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_EXTEND_NOT_EXIST);
                }
                //2.组装合并对象
                generateNewTransaction(bo, np, xinhua);
                log.info("{}-合并后数据组装主表记录：{}，扩展表记录：{}", LOG_MSG, JSONUtil.toJsonStr(np), JSONUtil.toJsonStr(xinhua));
                //更新被合并的流水
                int update = this.baseMapper.update(null, new LambdaUpdateWrapper<NvatTrandtadvaltaxsep>()
                        .set(NvatTrandtadvaltaxsep::getCfhbzt, CommonEnum.SPLIT_MERGE_STATUS_3.getKey())
                        .in(NvatTrandtadvaltaxsep::getRdid, bo.getRdids())
                        .eq(NvatTrandtadvaltaxsep::getCfhbzt, CommonEnum.SPLIT_MERGE_STATUS_1.getKey())
                        .eq(NvatTrandtadvaltaxsep::getLszt, CommonEnum.FLOW_INVOICE_STATUS_1.getKey())
                        .eq(NvatTrandtadvaltaxsep::getJyjg, SecurityUtils.getDeptCode())
                );
                log.info("{}-合并后数据更新流水状态返回：{}，", LOG_MSG, update);
                if (update != bo.getRdids().size()) {
                    //处理的数据和实际数据不一致
                    throw new BusinessException(ResponseEnum.MERGING_ERROR);
                }
                //3.保存合并后的流水
                if (this.save(np)) {
                    log.info("{}-合并后数据保存成功，rdid：{}，", LOG_MSG, np.getRdid());
                    xinhua.setRdid(np.getRdid());
                    nvatTrandtadvalextXinhuaService.save(xinhua);
                    //3.1 保存合并后的流水关联表
                    List<NvatRevenuemapself> sefs = new ArrayList<>();
                    List<Long> furdids = new ArrayList<>();
                    for (NvatTrandtadvaltaxsep p : tps) {
                        NvatRevenuemapself sef = new NvatRevenuemapself();
                        sef.setYrdid(p.getRdid());
                        sef.setXrdid(np.getRdid());
                        sef.setCzlx(CommonEnum.SPLIT_MERGE_TYPE_2.getKey());
                        sef.setCzsj(new Date());
                        sefs.add(sef);
                        //判断是否是负数流水，如果是负数流水，则处理负数流水表；
                        if (p.getJyje().compareTo(BigDecimal.ZERO) == -1) {
                            furdids.add(p.getRdid());
                            log.info("{}-合并后数据原数据存在负数流水，rdid：{}，", LOG_MSG, p.getRdid());
                        }
                    }
                    nvatRevenuemapselfService.saveBatch(sefs);
                    //3.2 如果原数据是负数流水， 处理负数流水表；
                    if (furdids.size() > 0) {
                        boolean n = nvatNegativestreamForVatService.update(new LambdaUpdateWrapper<NvatNegativestream>()
                                .set(NvatNegativestream::getClzt, CommonEnum.NEGATIVE_FLOW_STATUS_1.getKey())
                                .set(NvatNegativestream::getCzr, SecurityUtils.getUsername())
                                .set(NvatNegativestream::getCzrq, new Date())
                                .set(NvatNegativestream::getCllx, NegeClEnum.CLLX_04.getKey())
                                .set(NvatNegativestream::getCzsm, NegeClEnum.CLLX_04.getValue())
                                .in(NvatNegativestream::getRdid, furdids)
                                .eq(NvatNegativestream::getClzt, CommonEnum.NEGATIVE_FLOW_STATUS_0.getKey()));
                        log.info("{}-合并后数据处理原数据对应的负数流水表，{} ,共： {}，", LOG_MSG, n, furdids.size());
                    }
                    //3.3 如果合并之后数据是负数流水， 添加到负数流水表；
                    if (np.getJyje().compareTo(BigDecimal.ZERO) == -1) {
                        NvatNegativestream nvatNegativestream = new NvatNegativestream();
                        nvatNegativestream.setRdid(np.getRdid());
                        nvatNegativestream.setYwbh(np.getYsjyls());
                        nvatNegativestream.setFuywbh(np.getExpcol1());
                        nvatNegativestream.setTbr(np.getKhmc());
                        nvatNegativestream.setJyjg(np.getJyjg());
                        nvatNegativestream.setSbrq(new Date());
                        nvatNegativestream.setClzt(CommonEnum.NEGATIVE_FLOW_STATUS_0.getKey());
                        nvatNegativestream.setSfgz(CommonEnum.NEGATIVE_FLOW_MANAGE_0.getKey());
                        nvatNegativestreamForVatService.save(nvatNegativestream);
                        log.info("{}-合并后数据合并后数据是负数，增加到负数流水表：{} ，", LOG_MSG, JSONUtil.toJsonStr(nvatNegativestream));
                    }
                    return Result.OK("合并数据成功！");
                } else {
                    throw new BusinessException(ResponseEnum.MERGING_ERROR);
                }
            }
        }
        return Result.ERROR(ResponseEnum.MERGING_TRANSACTION_FLOW);
    }

    /**
     * 生成新流水信息
     *
     * @param bo
     * @param np
     */

    private static void generateNewTransaction(VmsMergeBo bo, NvatTrandtadvaltaxsep np, NvatTrandtadvalextXinhua xinhua) {
        //1.主表数据
        BeanUtils.copyProperties(bo, np); // 右侧对象 赋值到左侧
        np.setRdid(null);
        //交易人民币金额
        np.setJyrmbje(bo.getJyje());
        //负数流水和正数流水处理
        if (bo.getJyje().compareTo(BigDecimal.ZERO) == -1) { // 小于0
            np.setLsxz(Long.parseLong(CommonEnum.LSXZ_2.getKey()));
            np.setYsjyls(CommonConstant.YYWBH + bo.getYwbh());
        } else { // 大于0
            np.setLsxz(Long.parseLong(CommonEnum.LSXZ_1.getKey())); // -- 大于0,就设置为蓝字 ---- 流水性质：1蓝字（正常），2红字，3反向蓝字，4折扣，5冲正，6撤销 //对于5、6时，如外围系统无法提供必填字段，就在必须加工过来，或不在本系统保留（但如存在原流水已开票情时，5、6的处理一致，当作为冲正流水来看待，在原流水标识为已冲正）。
            np.setYsjyls(""); // 原业务交易号，即被红冲/折扣交易号
        }

        //未拆分合并
        np.setCfhbzt(Long.parseLong(CommonEnum.SPLIT_MERGE_STATUS_1.getKey()));
        //未开票
        np.setLszt(Long.parseLong(CommonEnum.FLOW_INVOICE_STATUS_1.getKey()));
        //供数日期当前时间
        np.setGsrq(new Date());
        //业务编号
        np.setExpcol1(bo.getYwbh());
        np.setExpcol3(bo.getXzdm());
        np.setExpcol4(bo.getXzjc());
        np.setKhmc(bo.getKfhm());
        np.setKhsjh(bo.getSjh());
        np.setKhemail(bo.getDzyx());
        //2.扩展表数据
        BeanUtils.copyProperties(bo, xinhua);
        xinhua.setBqxmdm("");
        xinhua.setBqxmmc("");
        xinhua.setJfjzrq(null);
        xinhua.setJfqsrq(null);
        xinhua.setFwrybh("");
        xinhua.setFwryxm("");
        xinhua.setQmc("");
        xinhua.setBmc("");
        xinhua.setZmc("");
        xinhua.setCpdm(bo.getXzdm());
        xinhua.setCpmc(bo.getXzjc());
        xinhua.setBz("");
        xinhua.setGgxh(bo.getXzdm());
        xinhua.setXmdj(bo.getBhsje());
        xinhua.setTbrxm(bo.getKfhm());
        xinhua.setXmsl(BigDecimal.ONE);
        xinhua.setHjdh("");
        xinhua.setXpxslh("");
        xinhua.setYwlx(CommonConstant.DBDHB_YWLX);
        xinhua.setSysbm("");
        xinhua.setJffs("");
    }

    /**
     * 合并数据 返回合并的对象集合
     * 预合并和正式合并公用改方法
     *
     * @param dto
     * @return
     */
    private List<VmsMergeBo> mergeRes(VmsMergeDto dto) {
        //1.验证数据并返回编号
        String bh = getBh(dto);
        String ywhh = null;
        String tbdh = null;
        if (CommonEnum.MERGE_QUERY_CONDITION_0.getKey().equals(dto.getMergeQueryCondition())) {
            ywhh = bh;
        } else {
            tbdh = bh;
        }
        //2.查询数据
        List<NvatTrandtadvaltaxsep> list = null; // 下面根据是否全部, 然后去查了sql
        if (dto.getAllMerge()) {
            //2.1 按投保单号或者业务编号获取全部数据
            list = this.baseMapper.mergeQuery(ywhh, tbdh, SecurityUtils.getDeptCode(), null); // 直接发请求了
        } else {
            //2.2 按业务编号或投保单号获取指定也就是选择的多个数据
            List<String> rdids = null;
            if (StringUtil.isNotBlank(dto.getRdids())) {
                rdids = Arrays.asList(dto.getRdids().split(","));
                list = this.baseMapper.mergeQuery(ywhh, tbdh, SecurityUtils.getDeptCode(), rdids);
            }
        }
        //3.合并数据
        HashMap<String, VmsMergeBo> map = new HashMap<>();
        if (CollectionUtil.isNotEmpty(list)) {
            for (NvatTrandtadvaltaxsep ntp : list) {
                //初始Key 是按税率
                String key = ntp.getSysl().toString(); // 初始化税率是key
                if (CommonEnum.MERGE_MODE_0.getKey().equals(dto.getMergeMode())) {
                    //如果模式是按险种代码， 增加险种底代码作为key
                    key += ntp.getExpcol3(); // 左侧是税率 + 险种代码 作为key
                }
                //如果map中没有key，则创建新的VmsMergeBo对象
                VmsMergeBo bo = map.computeIfAbsent(key, k -> new VmsMergeBo()); // 如果没有key,就直接给个实例.
                addVmsMergeBo(dto, ntp, bo, bh); // 第一个是传入的参数,第二个是list里的每个对象,第三个是右侧的对象(key在左侧),第三个是 根据类型获取的编号
            }
        }
        List<VmsMergeBo> values = new ArrayList<>();
        //4.合并后数据重新计算并转换
        if (map.size() > 0) {
            values = map.values().stream().map(e -> {
                //计算税额 税额=不含税金额*税率
                BigDecimal se = e.getBhsje().multiply(e.getSysl()); // 金额 * 税率
                //计算的税额和实际金额的差值
                BigDecimal ce = e.getXxse().subtract(se); // 税额 - 税额
                //如果差值大于0.06
                BigDecimal bigDecimalOne = new BigDecimal(CommonConstant.STR_1);
                if (ce.abs().compareTo(new BigDecimal(CommonConstant.STR_006)) > 0) { // 差额的绝对值大于0.06
                    log.info("{}-合并后数据税额误差大于0.06重新计算 计算前{}", LOG_MSG, JSONUtil.toJsonStr(e));
                    //不含税金额=含税金额/1+税率
                    e.setBhsje(e.getJyje().divide(bigDecimalOne.add(e.getSysl()), 2, RoundingMode.HALF_UP));
                    //税额=含税金额-不含税金额
                    e.setXxse(e.getJyje().subtract(e.getBhsje()));
                    log.info("{}-合并后数据税额误差大于0.06重新计算 计算后{}", LOG_MSG, JSONUtil.toJsonStr(e));
                }
                return e;
            }).collect(Collectors.toList());
        }
        return values;
    }

    /**
     * 合并数据,返回合并后的对象
     *
     * @param dto
     * @param ntp
     * @param bo
     * @param bh
     * @return
     */
    private VmsMergeBo addVmsMergeBo(VmsMergeDto dto, NvatTrandtadvaltaxsep ntp, VmsMergeBo bo, String bh) {// 第一个是传入的参数,第二个是list里的每个对象,第三个是右侧的对象(key在左侧),第三个是 根据类型获取的编号
        if (bo != null && CollectionUtil.isEmpty(bo.getRdids())) {
            //初始根据合并模式 险种代码和险种名称 简称进行赋值
            if (CommonEnum.MERGE_MODE_0.getKey().equals(dto.getMergeMode())) {
                bo.setXzdm(ntp.getExpcol3()); // 险种代码
                bo.setXzjc(ntp.getExpcol4()); // 险种简称
                bo.setXzqc(ntp.getYtbs1());//借用该字段返回的扩展表中的险种全称
            } else {
                bo.setXzdm("");
                bo.setXzjc(CommonConstant.BF);
                bo.setXzqc(CommonConstant.BF);
            }
            //证件类型号码 手机号 电子邮箱 纳税人识别号等进行赋值
            bo.setIssqyw("");
            bo.setIsgryw("");
            bo.setSjh(ntp.getYtbs2());//借用该字段返回的扩展表中的手机号
            bo.setZjlx(ntp.getYtbs3());//借用该字段返回的扩展表中的证件类型
            bo.setZjhm(ntp.getYtbs4());//借用该字段返回的扩展表中的证件号码
            bo.setTbdh(ntp.getYtbs7());//借用该字段返回的扩展表中的投保单号
            bo.setKfhm(ntp.getKfhm());
            bo.setDzyx(ntp.getYtbs8());//借用该字段返回的扩展表中的电子邮箱
            bo.setNsrsbh(ntp.getYtbs9());//借用该字段返回的扩展表中的纳税人识别号
            if (CommonEnum.MERGE_QUERY_CONDITION_1.getKey().equals(dto.getMergeQueryCondition())) { // 如果是1,就是 投保单号- 那bh重置?

                bh = String.format(CommonConstant.YWBH, ntp.getJyjg() // YWBH = 合并生成业务编号
                        , DateUtils.formatDate(new Date(), DateUtils.PURE_DATE_PATTERN)
                        , RandomUtil.randomNumbers(6));
            }
            bo.setYwbh(bh);
            bo.setSysl(ntp.getSysl());
            // 获取当前日期
            LocalDate currentDate = LocalDate.now();
            // 将日期转换为LocalDateTime，并将时分秒设为0
            LocalDateTime startOfDay = currentDate.atStartOfDay();
            // 将LocalDateTime转换为Date
            Date date = Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
            bo.setJyrq(date); // 交易日期

            List<Long> reids = new ArrayList<>();
            reids.add(ntp.getRdid());
            bo.setRdids(reids); // 添加rdid为rdids?

            bo.setBhsje(ntp.getBhsje()); // 不含税金额
            bo.setJyje(ntp.getJyje()); // 交易金额
            bo.setXxse(ntp.getXxse()); // 税额
            bo.setWkpje(ntp.getWkpje()); // 未开票金额
            return bo;
        }
        //对金额进行累加
        bo.setBhsje(bo.getBhsje().add(ntp.getBhsje()));
        bo.setJyje(bo.getJyje().add(ntp.getJyje()));
        bo.setXxse(bo.getXxse().add(ntp.getXxse()));
        bo.setWkpje(bo.getWkpje().add(ntp.getWkpje()));
        bo.getRdids().add(ntp.getRdid());
        if (bo.getKfhm() == null && !bo.getKfhm().equals(ntp.getKfhm())) {
            throw new BusinessException(ResponseEnum.MERGING_TRANSACTION_FLOW_ERROR);
        }
        return bo;
    }

    /**
     * 校验
     *
     * @param nvatTrandtadvaltaxsep 流水信息
     * @param xinhua                流水信息
     * @param dto                   拆分信息
     * @param fslsFlag              是否为负数流水
     * @param id                    流水ID
     * @return
     */
    private List<ErrorVerifyVo> verification(NvatTrandtadvaltaxsep nvatTrandtadvaltaxsep, NvatTrandtadvalextXinhua xinhua, VmsFlowSplitDto dto, boolean fslsFlag, Long id) { // 第一个参数是外层序列化对象

        // 1.2 流水是否是未开票状态
        if (!CommonEnum.FLOW_INVOICE_STATUS_1.getKey().equals(String.valueOf(nvatTrandtadvaltaxsep.getLszt()))) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_IS_NOT_UNPAID);
        }

        // 1.3 判断流水是否已拆分 或 已合并
        int count = nvatRevenuemapselfService.count(new LambdaQueryWrapper<NvatRevenuemapself>()
                .eq(NvatRevenuemapself::getYrdid, id)
        );
        if (count > 0) { // 为啥累加在一起,超过0,就报错呢
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_HAS_BEEN_SPLIT_OR_MERGED);
        }

        // 1.4 拆分信息必须大于一条
        List<VmsFlowSplitDto.VmsFlowSplitItem> item = dto.getItem();
        if (item.size() < 2) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_SPLIT_MUST_BE_GREATER_THAN_ONE);
        }

        // 1.5 校验拆分信息金额是否正确 并 对含税金额进行合计
        BigDecimal sumHsje = BigDecimal.ZERO;
        BigDecimal sumBhsje = BigDecimal.ZERO;
        BigDecimal sumSe = BigDecimal.ZERO;
        List<ErrorVerifyVo> errorVerifyVos = new ArrayList<>();
        for (int i = 0; i < item.size(); i++) {
            VmsFlowSplitDto.VmsFlowSplitItem vmsFlowSplitItem = item.get(i);
            // 校验 税额 是否正确
            if (!vmsFlowSplitItem.checkSe()) {
                ErrorVerifyVo errorVerifyVo = new ErrorVerifyVo();
                errorVerifyVo.setNum("第" + (i + 1) + "条拆分信息");
                errorVerifyVo.setKey("税额");
                errorVerifyVo.setValue("误差超过0.01");
                errorVerifyVos.add(errorVerifyVo);
            }
            // 如果是负数流水 那拆分的流水必须也是负数
            if (fslsFlag) { // 如果是负数流水
                validateAmount(i, vmsFlowSplitItem.getHsje(), "含税金额", true, errorVerifyVos);
                validateAmount(i, vmsFlowSplitItem.getBhsje(), "不含税金额", true, errorVerifyVos);
                validateAmount(i, vmsFlowSplitItem.getSe(), "税额", true, errorVerifyVos);
            } else { // 如果不是负数流水，即校验是否为正数
                validateAmount(i, vmsFlowSplitItem.getHsje(), "含税金额", false, errorVerifyVos);
                validateAmount(i, vmsFlowSplitItem.getBhsje(), "不含税金额", false, errorVerifyVos);
                validateAmount(i, vmsFlowSplitItem.getSe(), "税额", false, errorVerifyVos);
            }
            // 累加含税金额
            BigDecimal hsje = vmsFlowSplitItem.getHsje();
            sumHsje = sumHsje.add(hsje);
            // 累加不含税金额 和 税额
            sumBhsje = sumBhsje.add(vmsFlowSplitItem.getBhsje());
            sumSe = sumSe.add(vmsFlowSplitItem.getSe());
        }
        if (!errorVerifyVos.isEmpty()) {
            return errorVerifyVos;
        }

        // 1.6 校验含税金额是否和原流水含税金额一致
        if (sumHsje.compareTo(nvatTrandtadvaltaxsep.getJyje()) != 0) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_SPLIT_AMOUNT_INCONSISTENCY_01);
        }

        // 1.7 校验 累加不含税金额和税额 是否和原流水的不含税金额和税额相差小于等于0.06
        BigDecimal bd1 = sumBhsje.add(sumSe);
        BigDecimal bd2 = nvatTrandtadvaltaxsep.getBhsje().add(nvatTrandtadvaltaxsep.getXxse());
        if (bd1.subtract(bd2).abs().compareTo(new BigDecimal(CommonConstant.STR_006)) > 0) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_SPLIT_AMOUNT_INCONSISTENCY_02);
        }

        return null;
    }


    /**
     * 校验
     *
     * @param index
     * @param amount
     * @param key
     * @param shouldBeNegative
     * @param errors
     */
    private void validateAmount(int index, BigDecimal amount, String key, boolean shouldBeNegative, List<ErrorVerifyVo> errors) {
        if ((amount.compareTo(BigDecimal.ZERO) > 0) == shouldBeNegative) {
            ErrorVerifyVo error = new ErrorVerifyVo();
            error.setNum("第" + (index + 1) + "条拆分信息");
            error.setKey(key);
            error.setValue(shouldBeNegative ? "必须为负数" : "必须为正数");
            errors.add(error);
        }
    }

    public NvatTrandtadvaltaxsep getNvatTrandtadvaltaxsepById(Long id, boolean stateVerification) {
        if (ObjectUtil.isEmpty(id)) {
            return null;
        }
        return getOne(new LambdaQueryWrapper<NvatTrandtadvaltaxsep>()
                .eq(NvatTrandtadvaltaxsep::getRdid, id)
                .eq(stateVerification, NvatTrandtadvaltaxsep::getCfhbzt, CommonEnum.SPLIT_MERGE_STATUS_1.getKey())
                .eq(stateVerification, NvatTrandtadvaltaxsep::getLszt, CommonEnum.FLOW_INVOICE_STATUS_1.getKey())
                .eq(NvatTrandtadvaltaxsep::getJyjg, SecurityUtils.getDeptCode())
        );
    }

    @Override
    public Result<VmsFlowInvoiceDetailVo> getMergeSplitInfo(String id) {
        // 1. 先校验
        NvatRevenuemapself entity = nvatRevenuemapselfService.getRevenuemapselfByXrdid(id);
        if (ObjectUtil.isNull(entity)) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_DOES_NOT_EXIST);
        }
        // 校验流水是否已开票
        checkFlowInvoiceStatus(entity);
        // 2. 获取需要展示的数据
        VmsFlowInvoiceDetailVo mergeSplitInfo = new VmsFlowInvoiceDetailVo();
        // 拆分
        if (CommonEnum.SPLIT_MERGE_TYPE_1.getKey().equals(entity.getCzlx())) {
            mergeSplitInfo = baseMapper.getSplitInfo(id);
            log.info("{}-获取拆分信息成功,流水信息:{}", LOG_MSG, JSONUtil.toJsonStr(mergeSplitInfo));
        }
        // 合并
        if (CommonEnum.SPLIT_MERGE_TYPE_2.getKey().equals(entity.getCzlx())) {
            mergeSplitInfo = baseMapper.getMergeInfo(id);
            log.info("{}-获取合并信息成功,流水信息:{}", LOG_MSG, JSONUtil.toJsonStr(mergeSplitInfo));
        }

        return Result.OK(mergeSplitInfo);
    }

    public Result<IPage<VmsFlowInvoiceDetailVo>> getMergeSplitItem(VmsFlowInvoiceDetailDto dto) {
        Integer pageNo = dto.getPageNo();
        Integer pageSize = dto.getPageSize();
        NvatRevenuemapself entity = nvatRevenuemapselfService.getRevenuemapselfByXrdid(String.valueOf(dto.getRdid()));
        IPage<VmsFlowInvoiceDetailVo> page = new Page<>(pageNo, pageSize);
        // 拆分
        if (CommonEnum.SPLIT_MERGE_TYPE_1.getKey().equals(entity.getCzlx())) {
            page = baseMapper.getSplitItem(page, String.valueOf(dto.getRdid()));
            log.info("{}-获取拆分明细信息成功,流水信息:{}", LOG_MSG, JSONUtil.toJsonStr(page));
        }
        // 合并
        if (CommonEnum.SPLIT_MERGE_TYPE_2.getKey().equals(entity.getCzlx())) {
            page = baseMapper.getMergeItem(page, String.valueOf(dto.getRdid()));
            log.info("{}-获取合并明细信息成功,流水信息:{}", LOG_MSG, JSONUtil.toJsonStr(page));
        }


        return Result.OK(page);
    }


    public void checkFlowInvoiceStatus(NvatRevenuemapself entity) {
        Long id = entity.getXrdid();
        String czlx = entity.getCzlx();
        long count = 0;
        // 判断是合并还是拆分
        if (CommonEnum.SPLIT_MERGE_TYPE_1.getKey().equals(czlx)) {
            // 如果是拆分 需要查看 所有被拆分的流水 是否开票 开票的流水 不允许回退
            count = baseMapper.verifySplit(id);
        } else if (CommonEnum.SPLIT_MERGE_STATUS_2.getKey().equals(czlx)) {
            // 如果是合并 只需要查看这条合并流水 是否开票  开票的流水 不允许回退
            count = baseMapper.verifyMerge(id);
        }
        if (count > 0) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_HAS_BEEN_INVOICED);
        }
    }

    @Override
    public Result<Object> checkFlowInvoiceStatus(String id) {
        NvatRevenuemapself entity = nvatRevenuemapselfService.getRevenuemapselfByXrdid(id);
        log.info("{}-流水信息成功,流水信息:{}", LOG_MSG, entity.toString());
        checkFlowInvoiceStatus(entity);
        return Result.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> restoreFlow(String id) {
        NvatRevenuemapself entity = nvatRevenuemapselfService.getRevenuemapselfByXrdid(id);
        if (ObjectUtil.isNull(entity)) {
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_DOES_NOT_EXIST);
        }
        // 校验
        checkFlowInvoiceStatus(entity);
        // 判断是拆分还是合并
        if (CommonEnum.SPLIT_MERGE_TYPE_1.getKey().equals(entity.getCzlx())) {
            // 拆分
            restoreSplit(id);
        } else if (CommonEnum.SPLIT_MERGE_TYPE_2.getKey().equals(entity.getCzlx())) {
            // 合并
            restoreMerge(id);
        }
        return Result.OK();
    }

    private void restoreMerge(String id) {
        // 1. 获取合并信息 (需要被删除的数据)
        VmsFlowInvoiceDetailVo mergeInfo = baseMapper.getMergeInfo(id);
        // 2. 获取合并明细信息 (需要被还原的数据)
        List<VmsFlowInvoiceDetailVo> mergeItemList = baseMapper.getMergeItemList(id);
        // 3.还原被合并的数据
        boolean b = updateBatchById(mergeItemList.stream().map(vmsFlowInvoiceDetailVo -> {
            NvatTrandtadvaltaxsep taxsep = new NvatTrandtadvaltaxsep();
            taxsep.setRdid(vmsFlowInvoiceDetailVo.getRdid());
            taxsep.setCfhbzt(Long.valueOf(CommonEnum.SPLIT_MERGE_STATUS_1.getKey()));
            return taxsep;
        }).collect(Collectors.toList()));
        if (!b) {
            log.error("{}-合并流水-原流水信息恢复失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }

        // 4. 删除合并出来的内条数据
        boolean b1 = remove(new LambdaQueryWrapper<NvatTrandtadvaltaxsep>()
                .eq(NvatTrandtadvaltaxsep::getRdid, mergeInfo.getRdid())
        );
        if (!b1) {
            log.error("{}-合并流水-流水信息表,被合并流水删除失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 5. 删除流水扩展信息表信息
        boolean b2 = nvatTrandtadvalextXinhuaService.remove(new LambdaQueryWrapper<NvatTrandtadvalextXinhua>()
                .eq(NvatTrandtadvalextXinhua::getRdid, mergeInfo.getRdid())
        );
        if (!b2) {
            log.error("{}-合并流水-流水扩展信息表,删除失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 6. 删除合并关联表
        boolean b3 = nvatRevenuemapselfService.remove(new LambdaQueryWrapper<NvatRevenuemapself>()
                .eq(NvatRevenuemapself::getXrdid, id));
        if (!b3) {
            log.error("{}-合并流水-删除合并关联表失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 7. 负数流水
        ArrayList<Long> list = new ArrayList<>();
        // 7.1 先遍历,准备需要修改的数据
        for (VmsFlowInvoiceDetailVo vmsFlowInvoiceDetailVo : mergeItemList) {
            // 如果是负数 就说明是负数流水 肯定在负数流水表中存在
            if (vmsFlowInvoiceDetailVo.getJyje().compareTo(BigDecimal.ZERO) == -1) {
                list.add(vmsFlowInvoiceDetailVo.getRdid());
            }
        }
        // 7.2 如果 list 不等于空 就修改流水状态为 未处理状态
        if (list.size() > 0) {
            boolean b4 = nvatNegativestreamForVatService.update(new LambdaUpdateWrapper<NvatNegativestream>()
                    .set(NvatNegativestream::getClzt, CommonEnum.NEGATIVE_FLOW_STATUS_0.getKey())
                    .set(NvatNegativestream::getCzr, "")
                    .set(NvatNegativestream::getCzrq, "")
                    .set(NvatNegativestream::getCllx, "")
                    .set(NvatNegativestream::getCzsm, "")
                    .in(NvatNegativestream::getRdid, list)
            );
            if (!b4) {
                log.error("{}-合并流水-修改负数流水表失败,流水ID:{}", LOG_MSG, id);
                throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
            }
        }
        // 7.3 删除被合并出来的流水信息 先判断是否为负数 是的话就删除掉
        if (mergeInfo.getJyje().compareTo(BigDecimal.ZERO) == -1) {
            boolean b5 = nvatNegativestreamForVatService.remove(new LambdaQueryWrapper<NvatNegativestream>()
                    .eq(NvatNegativestream::getRdid, mergeInfo.getRdid())
            );
            if (!b5) {
                log.error("{}-合并流水-删除负数流水表失败,流水ID:{}", LOG_MSG, id);
                throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
            }
        }
    }

    private void restoreSplit(String id) {
        // 1. 获取被拆分信息
        VmsFlowInvoiceDetailVo splitInfo = baseMapper.getSplitInfo(id);
        // 2. 获取拆分明细信息
        List<VmsFlowInvoiceDetailVo> splitItemList = baseMapper.getSplitItemList(id);
        List<Long> collect = splitItemList.stream().map(VmsFlowInvoiceDetailVo::getRdid).collect(Collectors.toList());
        // 3. 判断是否为负数流水
        NvatTrandtadvaltaxsep taxsep = getNvatTrandtadvaltaxsepById(splitInfo.getRdid(), false);
        boolean fslsFlag = taxsep.getJyje().compareTo(BigDecimal.ZERO) == -1;

        // 4.恢复被拆分流水状态
        taxsep.setCfhbzt(Long.valueOf(CommonEnum.SPLIT_MERGE_STATUS_1.getKey()));
        boolean b = updateById(taxsep);
        if (!b) {
            log.error("{}-拆分流水-原流水信息恢复失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 5.删除流水表信息
        boolean b1 = removeByIds(collect);
        if (!b1) {
            log.error("{}-拆分流水-明细信息恢复失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 6.删除流水扩展信息表信息
        boolean b2 = nvatTrandtadvalextXinhuaService.removeByIds(collect);
        if (!b2) {
            log.error("{}-拆分流水-扩展信息恢复失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 7.删除拆分关联表
        boolean b3 = nvatRevenuemapselfService.remove(new LambdaQueryWrapper<NvatRevenuemapself>()
                .eq(NvatRevenuemapself::getYrdid, id));
        if (!b3) {
            log.error("{}-拆分流水-删除拆分关联表失败,流水ID:{}", LOG_MSG, id);
            throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
        }
        // 8.删除拆分出来的 负数流水
        if (fslsFlag) {
            // 8.1 先修改之前流水 改为未处理状态
            boolean b4 = nvatNegativestreamForVatService.update(new LambdaUpdateWrapper<NvatNegativestream>()
                    .set(NvatNegativestream::getClzt, CommonEnum.NEGATIVE_FLOW_STATUS_0.getKey())
                    .set(NvatNegativestream::getCzr, "")
                    .set(NvatNegativestream::getCzrq, "")
                    .set(NvatNegativestream::getCllx, "")
                    .set(NvatNegativestream::getCzsm, "")
                    .eq(NvatNegativestream::getRdid, splitInfo.getRdid()));
            if (!b4) {
                log.error("{}-拆分流水-修改负数流水表失败,流水ID:{}", LOG_MSG, id);
                throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
            }

            // 8.2 删除被拆分出来的流水信息
            boolean b5 = nvatNegativestreamForVatService.remove(new LambdaQueryWrapper<NvatNegativestream>()
                    .in(NvatNegativestream::getRdid, collect));
            if (!b5) {
                log.error("{}-拆分流水-删除负数流水表失败,流水ID:{}", LOG_MSG, id);
                throw new BusinessException(ResponseEnum.TRANSACTION_FLOW_INFORMATION_RECOVERY_FAILED);
            }
        }
    }

}




